import {
  heavenStems,
  getSixtyYearsCycle,
  sixtyFourDiagrams,
  basicEightDiagrams,
  sixGods,
  relation,
  getBorn,
  monthBranchRate,
  dayBranchRate,
} from "./consts.js";

import { fiveElements, sixMembers } from "./enums.js";

export default {
  getDead(day) {
    const ret = [];
    let finish = false;
    if (day && day.length == 2) {
      const cycles = getSixtyYearsCycle();
      const index = cycles.findIndex(
        (x) => x.heavenStem.name == day[0] && x.earthBranch.name == day[1]
      );
      for (let i = index; i < cycles.length; i++) {
        if (cycles[i].heavenStem.name == heavenStems.癸.name) {
          let current = i + 1;
          for (let j = 0; j < 2; j++) {
            if (current == cycles.length) current = 0;
            ret.push(cycles[current]);
            current++;
            finish = true;
          }
        }
        if (finish) break;
      }
    }
    return ret;
  },
  getDiagram(symbols) {
    const booleans = convertSymbols2Booleans(symbols);

    const diagrams = Object.keys(sixtyFourDiagrams);
    for (let i = 0; i < diagrams.length; i++) {
      const diagram = sixtyFourDiagrams[diagrams[i]];
      const symbols = diagram.bottom.symbols.concat(diagram.top.symbols);
      if (symbols.toString() == booleans.toString()) return diagram;
    }
    return null;
  },

  getDiagramName(diagram) {
    switch (diagram.name) {
      case "乾":
        return "乾为天（六冲）";
      case "坤":
        return "坤为地（六冲）";
      case "坎":
        return "坎为水（六冲）";
      case "艮":
        return "艮为山（六冲）";
      case "震":
        return "震为雷（六冲）";
      case "巽":
        return "巽为风（六冲）";
      case "离":
        return "离为火（六冲）";
      case "兑":
        return "兑为泽（六冲）";
      case "大壮":
        return "雷天大壮（六冲）";
      case "无妄":
        return "天雷无妄（六冲）";
      case "否":
        return "天地否（六合）";
      case "泰":
        return "地天泰（六合）";
      case "节":
        return "水泽节（六合）";
      case "困":
        return "泽水困（六合）";
      case "贲":
        return "山火贲（六合）";
      case "旅":
        return "火山旅（六合）";
      case "复":
        return "地雷复（六合）";
      case "豫":
        return "雷地豫（六合）";

      default:
        return (
          diagram.top.diagramElement.name +
          diagram.bottom.diagramElement.name +
          diagram.name +
          "（" +
          diagram.host.name +
          diagram.eachOther.name +
          "）"
        );
    }
  },
  getEachOther(diagram) {
    let other = diagram.eachOther.level + 3;
    other = [other > 5 ? other - 6 : other];

    return {
      each: diagram.eachOther.level,
      other,
    };
  },
  getSixGods(day) {
    const keys = Object.keys(sixGods);
    const ret = [];
    if (day) {
      let i = Object.values(sixGods).findIndex(
        (x) => x.element == heavenStems[day[0]].element
      );

      if (heavenStems[day[0]].name == "己") i++;

      let count = 0;

      while (count < 6) {
        if (i == keys.length) {
          i = 0;
        }

        ret.push(keys[i]);

        i++;
        count++;
      }
    }
    return ret;
  },
  changeDiagram(symbols) {
    return symbols.map((x) => {
      if (x == 6) {
        return 7;
      } else if (x == 9) return 8;
      else return x;
    });
  },
  getSixMembers(diagram, baseElement) {
    const branches = diagram.bottom.earthBranches
      .slice(0, 3)
      .concat(diagram.top.earthBranches.slice(3));

    const stems = diagram.bottom.heavenStems
      .slice(0, 1)
      .concat(diagram.bottom.heavenStems.slice(0, 1))
      .concat(diagram.bottom.heavenStems.slice(0, 1))
      .concat(diagram.top.heavenStems.slice(1))
      .concat(diagram.top.heavenStems.slice(1))
      .concat(diagram.top.heavenStems.slice(1));

    const ret = branches.map((x, i) => {
      return {
        earthBranch: x,
        heavenStem: stems[i],
        sixMember: this.getSixMember(
          baseElement || diagram.host.element,
          x.element
        ),
      };
    });

    return ret;
  },

  getSixMember(baseElement, targetElement) {
    const keys = Object.keys(fiveElements);
    const baseIndex = keys.indexOf(baseElement.name);
    const targetIndex = keys.indexOf(targetElement.name);
    const sixMemberKeys = Object.keys(sixMembers);

    const offset = targetIndex - baseIndex;

    if (offset >= 0) return sixMembers[sixMemberKeys[offset]];
    else return sixMembers[sixMemberKeys[5 + offset]];
  },

  randomSymbols(mode = "hexagram") {
    const ret = [];
    const change = Math.floor(Math.random() * 6);
    for (let i = 0; i < 6; i++) {
      let symbol =
        Math.floor(Math.random() * 2) +
        2 +
        (Math.floor(Math.random() * 2) + 2) +
        (Math.floor(Math.random() * 2) + 2);

      if (mode == "plumagram") {
        if (symbol == 6) {
          symbol = 8;
        }
        if (symbol == 9) {
          symbol = 7;
        }
        if (i == change) {
          if (symbol == 8) {
            symbol = 6;
          }
          if (symbol == 7) {
            symbol = 9;
          }
        }
      }
      ret.push(symbol);
    }
    return ret;
  },
  getPlumSymbols(data) {
    const topNumbers = Math.floor(Math.abs(data[0] || 8) % 8) || 8;

    let topDiagram;
    for (const key in basicEightDiagrams) {
      if (basicEightDiagrams[key].ancientNumber == topNumbers) {
        topDiagram = basicEightDiagrams[key];
        break;
      }
    }
    const bottomNumbers = Math.floor(Math.abs(data[1] || 8) % 8) || 8;
    let bottomDiagram;
    for (const key in basicEightDiagrams) {
      if (basicEightDiagrams[key].ancientNumber == bottomNumbers) {
        bottomDiagram = basicEightDiagrams[key];
        break;
      }
    }

    const change = (Math.floor(Math.abs(data[2] || 6) % 6) || 6) - 1;
    const symbols = bottomDiagram.symbols
      .concat(topDiagram.symbols)
      .map((x) => (x ? 7 : 8));

    if (symbols[change] == 8) symbols[change] = 6;
    if (symbols[change] == 7) symbols[change] = 9;
    return symbols;
  },

  getHighLight(highlights, earthBranch) {
    return highlights.find((x) => x.factors.includes(earthBranch));
  },

  /**
   *
   * @param {*} sixMembers 包含地支信息六个爻
   * @param {[]} noUse 无用的爻有哪几个（无用爻的索引数组，例如[0,1,3]）
   * @param {string} monthBranch 月支名称
   * @param {string} dateBranch 日支名称
   * @param {string} dead 2个空亡名称
   * @returns 返回需要加哪些特效
   */
  getDecoration(sixMembers, symbols, noUse, monthBranch, dateBranch, dead) {
    const ret = ["", "", "", "", "", ""];

    for (let i = 0; i < sixMembers.length; i++) {
      if (noUse.includes(i)) continue;

      const sixMember = sixMembers[i];
      if (dead.includes(sixMember.earthBranch.name)) {
        ret[i] += "dead ";
      }

      const impactFactors = relation.impact.find(
        (x) =>
          x.factors.find((x) => x.name == sixMember.earthBranch.name) != null
      ).factors;

      impactFactors.forEach((x) => {
        if (x.name != sixMember.earthBranch.name) {
          if (x.name == monthBranch) {
            //月支六冲
            if (sixMember.rate < 0) ret[i] += "month-break ";
            else ret[i] += "month-half-break ";
          }
          if (x.name == dateBranch) {
            if (sixMember.rate >= 0 || ret[i].includes("dead")) ret[i] += "active ";
            else {
              const borns = getBorn(sixMember.earthBranch);
              for (let j = 0; j < symbols.length; j++) {
                //如果日破之爻得任一动爻相生，则也属于暗动
                if (symbols[j] == 6 || symbols[j] == 9) {
                  if (
                    borns
                      .map((y) => y.name)
                      .indexOf(sixMembers[j].earthBranch.name) > -1
                  ) {
                    ret[i] += "active ";
                    break;
                  }
                }
              }
              if (symbols[i] == 6 || symbols[i] == 9)
                ret[i] += "day-half-break ";
              else ret[i] += "day-break ";
            }
          }
        }
      });

      //本卦中静爻如果旺相，平相也算，并且被本卦中其他动爻来冲，也构成暗动
      if (sixMember.rate >= 0 && !ret[i].includes("active")) {
        if (symbols[i] == 7 || symbols[i] == 8) {
          for (let j = 0; j < symbols.length; j++) {
            if (
              (symbols[j] == 6 || symbols[j] == 9) &&
              sixMember.earthBranch.name != sixMembers[j].earthBranch.name
            ) {
              const factors = relation.impact.find((x) =>
                x.factors.find((y) => y.name == sixMembers[j].earthBranch.name)
              ).factors;
              if (factors.find((x) => x.name == sixMember.earthBranch.name))
                ret[i] += "active inner ";
            }
          }
        }
      }
    }
    return ret;
  },

  computeHexagramRate(sixMembers, noUse, monthBranch, dateBranch) {
    for (let i = 0; i < sixMembers.length; i++) {
      if (noUse.includes(i)) continue;
      const sixMember = sixMembers[i];
      let rate = monthBranchRate[monthBranch][sixMember.earthBranch.name];
      rate += dayBranchRate[dateBranch][sixMember.earthBranch.name];
      sixMember.rate = rate;
    }
  },
};

function convertSymbols2Booleans(symbols) {
  if (symbols && symbols.length == 6) {
    return symbols.map((x) => x == 7 || x == 9);
  }
  return [];
}
